package com.sinodata.bsm.center.util;

import java.util.Properties;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.jboss.remoting.samples.chat.exceptions.InitializeException;

/**
 * 
 * <p>
 * Description: 
 * </p>
 *
 * @author tangli
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-6-13 PM 1:34:34     tangli         1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class ThreadPool {

    private static final Logger logger = Logger.getLogger(ThreadPool.class);

    private static ThreadPool instance = null;

    private int corePoolSize = 50;

    private int maximumPoolSize = 500;

    private long keepAliveTime = 60;

    private final int maxQueueSize = 1000;

    private LinkedBlockingQueue<Runnable> workqueue = null;

    private final BlockThreadPool poolExecutor;

    /**
     * 线程池管理器
     */
    private ThreadPool() {
        if (workqueue == null) {
            workqueue = new LinkedBlockingQueue<Runnable>(maxQueueSize);
        }
        poolExecutor = new BlockThreadPool(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workqueue);
    }

    public synchronized static ThreadPool getInstance() {
        if (instance == null) {
            instance = new ThreadPool();
        }
        return instance;
    }

    /**
     * 初始化线程池
     */
    public void init() {
        poolExecutor.setCorePoolSize(corePoolSize);
        poolExecutor.setMaximumPoolSize(maximumPoolSize);
        poolExecutor.setKeepAliveTime(keepAliveTime, TimeUnit.SECONDS);
    }

    /**
     * 初始化线程池性能参数;
     * 
     * @param corePoolSize
     * @param maximumPoolSize
     * @param keepAliveTime
     *            单位为秒
     * @throws InitializeException
     */
    public void init(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepAliveTime = keepAliveTime;
        init();
    }

    /**
     * 根据prop中的参数进行初始化
     * @param prop
     * @throws InitializeException
     */
    public void init(Properties prop) {
        this.corePoolSize = Integer.parseInt(prop.getProperty("pool.corePoolSize"));
        this.maximumPoolSize = Integer.parseInt(prop.getProperty("pool.maximumPoolSize"));
        this.keepAliveTime = Long.parseLong(prop.getProperty("pool.keepAliveTime"));
        init();
    }

    /**
     * 执行一个任务
     * 
     * @param r
     */
    public synchronized void execute(Runnable r) {
        while (this.poolExecutor.getPoolSize() == this.maximumPoolSize && this.workqueue.size() == maxQueueSize) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                logger.error("Thread pool execute wait throw InterruptedException", e);
            }
        }
        this.poolExecutor.execute(r);
    }

    protected synchronized void endTask() {
        this.notifyAll();
    }

}

class BlockThreadPool extends ThreadPoolExecutor {

    public BlockThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public BlockThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public BlockThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    public BlockThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    /* (non-Javadoc)
     * @see java.util.concurrent.ThreadPoolExecutor#afterExecute(java.lang.Runnable, java.lang.Throwable)
     */

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        ThreadPool.getInstance().endTask();
    }

}
